﻿<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
    <!-- 
    Copyright 2010 Colin Rhodes.  
    Reproduction or distribution without prior written permission is prohibited. 
    
    This is an alpha version.  Contact colin.rhodes [at] gmail [dot] com for updates.
    -->
    <title>WatSplit Alpha</title>
    <meta name="apple-mobile-web-app-capable" content="yes" />
    <script type="text/javascript" src="prototype_1.6.1.js"></script>
    <script type="text/javascript">
        function $(element) {
            if (Object.isString(element))
                return document.getElementById(element);
            return element;
        }
        function Racer(racer) {
            this.Bib = racer.Bib;
            this.FName = racer.FName;
            this.LName = racer.LName;
            this.Team = racer.Team;
            this.Category = racer.Category;
            this.Start = racer.Start;
            this.LapCount = 0;
            this.Splits = new Array();
        }
        function initializeStartListEntries(entries) {
            var list = new Array();
            for (var i = 0, len = entries.length; i < len; ++i) {
                var racer = new Racer(entries[i]);
                list[racer.Bib] = racer;
            }
            return list;
        }
    
        var showTimesRelativeToLast = true;
        var startlist = { 
            "RaceName": "Test Race SM 10km Free",
            "Entries": initializeStartListEntries([
                { "Bib": 100, "FName": "John100", "LName": "Smith100", "Team": "Team100", "Category": "SM", "Start": 300 },
                { "Bib": 101, "FName": "John101", "LName": "Smith101", "Team": "Team101", "Category": "SM", "Start": 330 },
                { "Bib": 102, "FName": "John102", "LName": "Smith102", "Team": "Team102", "Category": "SM", "Start": 360 },
                { "Bib": 103, "FName": "John103", "LName": "Smith103", "Team": "Team103", "Category": "SM", "Start": 390 },
                { "Bib": 104, "FName": "John104", "LName": "Smith104", "Team": "Team104", "Category": "SM", "Start": 420 },
                { "Bib": 105, "FName": "John105", "LName": "Smith105", "Team": "Team105", "Category": "SM", "Start": 450 },
                { "Bib": 106, "FName": "John106", "LName": "Smith106", "Team": "Team106", "Category": "SM", "Start": 480 },
                { "Bib": 107, "FName": "John107", "LName": "Smith107", "Team": "Team107", "Category": "SM", "Start": 510 },
                { "Bib": 108, "FName": "John108", "LName": "Smith108", "Team": "Team108", "Category": "SM", "Start": 540 },
                { "Bib": 109, "FName": "John109", "LName": "Smith109", "Team": "Team109", "Category": "SM", "Start": 570 },
                { "Bib": 110, "FName": "John110", "LName": "Smith110", "Team": "Team110", "Category": "SM", "Start": 600 },
                { "Bib": 111, "FName": "John111", "LName": "Smith111", "Team": "Team111", "Category": "SM", "Start": 630 },
                { "Bib": 112, "FName": "John112", "LName": "Smith112", "Team": "Team112", "Category": "SM", "Start": 660 },
                { "Bib": 113, "FName": "John113", "LName": "Smith113", "Team": "Team113", "Category": "SM", "Start": 690 },
                { "Bib": 114, "FName": "John114", "LName": "Smith114", "Team": "Team114", "Category": "SM", "Start": 720 },
                { "Bib": 115, "FName": "John115", "LName": "Smith115", "Team": "Team115", "Category": "SM", "Start": 750 },
                { "Bib": 116, "FName": "John116", "LName": "Smith116", "Team": "Team116", "Category": "SM", "Start": 780 },
                { "Bib": 117, "FName": "John117", "LName": "Smith117", "Team": "Team117", "Category": "SM", "Start": 810 },
                { "Bib": 118, "FName": "John118", "LName": "Smith118", "Team": "Team118", "Category": "SM", "Start": 840 },
                { "Bib": 119, "FName": "John119", "LName": "Smith119", "Team": "Team119", "Category": "SM", "Start": 870 },
                { "Bib": 120, "FName": "John120", "LName": "Smith120", "Team": "Team120", "Category": "SM", "Start": 900 },
                { "Bib": 121, "FName": "John121", "LName": "Smith121", "Team": "Team121", "Category": "SM", "Start": 930 },
                { "Bib": 122, "FName": "John122", "LName": "Smith122", "Team": "Team122", "Category": "SM", "Start": 960 },
                { "Bib": 123, "FName": "John123", "LName": "Smith123", "Team": "Team123", "Category": "SM", "Start": 990 }
            ])
        };

        function LapEntry(racer, timestamp) {
            this.LapNumber = racer.LapCount;
            this.Bib = racer.Bib;
            this.Timestamp = timestamp;
            this.DisplayTimestamp = "";
            this.Element = CreateDisplayRow(this);
        }
        function Lap(lapNum) {
            this.LapNumber = lapNum;
            this.Entries = new Array();
        }
        Lap.prototype.AddEntry = function(entry) {
            // insert into the array, keeping timestamp sorted from smallest to largest
            var newList = new Array();
            var entryIdx = 0;
            var numEntries = this.Entries.length;
            
            // copy over entries with smaller timestamp
            for (; entryIdx < numEntries; ++entryIdx) {
                if (this.Entries[entryIdx].Timestamp <= entry.Timestamp)
                    newList.push(this.Entries[entryIdx]);
                else
                    break;
            }
            // copy over new entry
            newList.push(entry);
            // copy over entries with larger timestamp
            for (; entryIdx < numEntries; ++entryIdx)
                newList.push(this.Entries[entryIdx]);

            this.Entries = newList;
        }
        function Results() {
            this.Laps = new Array();
        }
        Results.prototype.AddSplit = function(racer, date) {
            var timestamp = parseInt(date.getTime() / 1000) - racer.Start;

            racer.LapCount++;
            racer.Splits[racer.LapCount] = timestamp;

            // get the lap collection (add if required)
            var lap = this.Laps[racer.LapCount];
            if (lap == undefined) {
                lap = new Lap(racer.LapCount);
                this.Laps[racer.LapCount] = lap;
            }

            // add a new lap entry for this racer, with a split of now
            lap.AddEntry(new LapEntry(racer, timestamp));
        };

        var results = new Results();
    </script>
    <script type="text/javascript">
        function LoadData() {
            $('raceTitle').innerHTML = startlist.RaceName;
            ShowMain();
        }
        function ShowMain() {
            $('bibEntry').style.display = 'none';
            $('main').style.display = '';
            $('border').style.backgroundColor = "White";
        }
        function ShowBibEntry() {
            $('bibEntry').style.display = '';
            $('main').style.display = 'none';
            $('border').style.backgroundColor = "Gray";
        }
        
        function StartBibEntry() {
            $('bibEntry_bib').value = "";
            ShowBibEntry();
        }
        function CanceBibEntryClick() {
            ShowMain();
        }
        function NumberClick(num) {
            $('bibEntry_bib').value += num;
        }
        function BackspaceClick() {
            var oldValue = $('bibEntry_bib').value;
            $('bibEntry_bib').value = oldValue.substr(0, oldValue.length - 1);
        }
        function TakeSplit() {
            $('bibError').style.display = 'none';
        
            var bib = parseInt($('bibEntry_bib').value);
            if (bib == NaN) {
                $('bibError').style.display = '';
                return;
            }

            var racer = startlist.Entries[bib];
            if (racer == undefined) {
                $('bibError').style.display = '';
                return;
            }

            results.AddSplit(racer, new Date());

            UpdateDisplay(racer);
            
            ShowMain();
        }
        function UpdateDisplay(racer) {
            var lap = results.Laps[racer.LapCount];

            // get the reference timestamp
            var referenceTimestamp;
            if (showTimesRelativeToLast)
                referenceTimestamp = racer.Splits[racer.LapCount];
            else
                referenceTimestamp = lap.Entries[0].Timestamp;

            // clear rows
            $('results').childElements().each(function(elem) { elem.remove(); });  // TODO: don't use prototype


            // set all of the display timestamps and add rows to UI
            for (var i = 0, len = lap.Entries.length; i < len; ++i) {
                var e = lap.Entries[i];
                e.DisplayTimestamp = FormatTime(e.Timestamp - referenceTimestamp);
                e.Element.getElementsByClassName('time')[0].innerHTML = e.DisplayTimestamp;  // TODO: don't use prototype
                $('results').insert({ bottom: e.Element });  // TODO: don't use prototype
            }
        }
        function FormatTime(totalSeconds) {
            var sign = totalSeconds < 0 ? "-" : "+";

            totalSeconds = totalSeconds < 0 ? ~totalSeconds++ : totalSeconds; // faster version of Math.abs(..)
            var sec = totalSeconds % 60;
            var min = (totalSeconds - sec) / 60;

            if (min < 10)
                min = "0" + min;
             if (sec < 10)
                sec = "0" + sec;

            return sign + min + ":" + sec;
        }
        function CreateDisplayRow(lapEntry) {  // TODO: don't use prototype
            var racer = startlist.Entries[lapEntry.Bib];
            
            var row = MakeElement('div', 'row');

            var bib = MakeElement('div', 'bib');
            bib.insert({ bottom: lapEntry.Bib });
            row.insert({ bottom: bib });

            var name = MakeElement('div', 'name');
            name.insert({ bottom: racer.FName + " " + racer.LName });
            row.insert({ bottom: name });

            var club = MakeElement('div', 'team');
            club.insert({ bottom: racer.Team });
            row.insert({ bottom: club });

            var time = MakeElement('div', 'time');
            time.insert({ bottom: lapEntry.DisplayTimestamp });
            row.insert({ bottom: time });

            return row;
        }
        function MakeElement(type, className) {  // TODO: don't use prototype
            var elem = new Element(type);
            elem.addClassName(className);
            return elem;
        }
    </script>
    <style type="text/css">
        div#border { position: relative; height: 460px; width: 310px; border:solid thin black; }
        div#title { width: 100%; height: 20px; font-weight: bold; background: gray; text-align: center; }
        
        div#results { width: 100%; height: 360px; }
        div#results div.row { position: relative; width: 300px; height: 40px; padding: 2px 4px 2px 4px; border: solid thin black; background-color: #CCCCCC; font-size: 9pt; }
        div#results div.row div { position: absolute; top: 2px; }
        div#results div.row div.bib { left: 4px; width: 20px; }
        div#results div.row div.name { left: 30px; width: 150px; }
        div#results div.row div.team { left: 190px; width: 50px; }
        div#results div.row div.time { left: 250px; width: 50px; }
       
        div#controls { width: 100%; height: 80px; border-top: solid thin black; }
        div#controls div.row { width: 100%; margin: 2px 0 2px 0; text-align: center; }
        div#controls div#enterRacer { width: 200px; font-size: 16pt; background-color: #CCFFCC;  border: solid thin gray; }

        div#bibEntry { position: absolute; top: 40px; left: 15px; width: 276px; height: 380px; border: solid thin black; background-color: #CCFFCC; }
        div#bibEntry div.number { position:absolute; width: 80px; height: 60px; border: solid thin gray; text-align: center; background-color: #CCCCCC; }
        div#bibEntry div.number div { position: relative; font-size: 18pt; font-weight: bold; top: 15px; }
        div#bibEntry .r1 { top: 8px; }
        div#bibEntry .r2 { top: 76px; }
        div#bibEntry .r3 { top: 144px; }
        div#bibEntry .r4 { top: 212px; }
        div#bibEntry .c1 { left: 8px; }
        div#bibEntry .c2 { left: 96px; }
        div#bibEntry .c3 { left: 184px; }
        div#bibEntry #bibEntry_bib { position:absolute; top: 284px; left: 8px; width: 254px; font-size: 18pt; font-weight: bold; }
        div#bibEntry #takeSplitButton { position:absolute; top: 324px; left: 8px; width: 258px; height: 30px; border: solid thin black; font-size: 18pt; font-weight: bold; text-align: center; background-color: #00FF00; }
        div#bibEntry #bibError { position:absolute; top: 356px; left: 8px; width: 260px; font-size: 12pt; color: Red; font-weight: bold; background-color: White; text-align: center; }
    </style>
</head>
<body>
    <div id="border">
        <div id="main">
            <div id="title">WatSplit - <span id="raceTitle"></span></div>
            <div id="results"></div>
            <div id="controls">
                <div class="row">
                    <center>
                        <div id="enterRacer" onclick="StartBibEntry()">Enter Racer</div>
                    </center>
                </div>
            </div>
        </div>
        <div id="bibEntry">
            <div class="number r1 c1" onclick="NumberClick(1)"><div>1</div></div>
            <div class="number r1 c2" onclick="NumberClick(2)"><div>2</div></div>
            <div class="number r1 c3" onclick="NumberClick(3)"><div>3</div></div>
            <div class="number r2 c1" onclick="NumberClick(4)"><div>4</div></div>
            <div class="number r2 c2" onclick="NumberClick(5)"><div>5</div></div>
            <div class="number r2 c3" onclick="NumberClick(6)"><div>6</div></div>
            <div class="number r3 c1" onclick="NumberClick(7)"><div>7</div></div>
            <div class="number r3 c2" onclick="NumberClick(8)"><div>8</div></div>
            <div class="number r3 c3" onclick="NumberClick(9)"><div>9</div></div>
            <div class="number r4 c1" onclick="NumberClick(0)"><div>0</div></div>
            <div class="number r4 c2" onclick="BackspaceClick()"><div>&lt;--</div></div>
            <div class="number r4 c3" onclick="CanceBibEntryClick()" style="background-color: #FF6666;"><div style="font-size: 14pt;">Cancel</div></div>
            
            <input type="text" id="bibEntry_bib" />
            <div id="takeSplitButton" onclick="TakeSplit()">Split</div>
            <div id="bibError" style="display: none;">Unknown Bib</div>
        </div>
    </div>
    <script type="text/javascript">
        Event.observe(window, 'load', function() {
            LoadData();
        });
    </script>
</body>
</html>
